package com.dianping.statistics;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.os.Handler;
import android.os.Message;

import com.dennytech.tac.net.HttpClientFactory;
import com.dennytech.tac.net.HttpClientFactory.MyHttpClient;
import com.dennytech.tac.utils.Daemon;
import com.dennytech.tac.utils.DataCursor;
import com.dennytech.tac.utils.Log;

public class StatisticsManager {
	private static final String TAG = StatisticsManager.class.getSimpleName();

	public static String URL = "http://stat.api.dianping.com/utm.js?v=androidv1";
	final static int COUNT = 16;
	final static int MAX = 64;
	final static int UPLOAD_INTERVAL = 15000;
	final static int CHECK_AND_UPLOAD = 1;
	final static int FORCE_UPLOAD = 2;
	final static int ADD_ITEM = 3;

	StatisticsDB sdb;

	class StatisticsHandler extends Handler {
		public StatisticsHandler() {
			super(Daemon.looper());
		}

		@Override
		public void handleMessage(Message msg) {
			Log.i(TAG, "handleMessage msg.what = " + msg.what);
			if (msg.what == CHECK_AND_UPLOAD) {
				if ((sdb != null) && (sdb.count() >= COUNT)) {
					doUpload();
				}
			} else if (msg.what == FORCE_UPLOAD) {
				doUpload();
			} else if (msg.what == ADD_ITEM) {
				String data = (String)msg.obj;
				if (sdb != null) {
					int sdbCount = sdb.count();
					if (sdbCount < MAX) {
						if (sdb.push(data) > 0) {
							if (sdbCount >= COUNT) {
								doUpload();
							} else if (sdbCount == 0) {
								removeMessages(FORCE_UPLOAD);
								sendEmptyMessageDelayed(FORCE_UPLOAD, UPLOAD_INTERVAL);
							}
						}
					}
				} else {
					//doUpload(data.getBytes());
				}
			}
		}
	}
	final Handler handler = new StatisticsHandler();
	private boolean closed;

	public StatisticsManager(Context context, String name) {
		if (context == null) {
			return;
		}

		SQLiteDatabase db = null;
		try {
			db = context.getApplicationContext().openOrCreateDatabase(
				name, 0, null);
		} catch (SQLiteException e) {
		}

		if (db != null) {
		    sdb = new StatisticsDB(db);
		}
	}

	private void doUpload() {
		if (closed)
			return;
		if (sdb == null) {
			return;
		}

		if (sdb.count() == 0)
			return;

		long maxId = sdb.maxId();
		ByteArrayOutputStream os = new ByteArrayOutputStream(0xFFF);
		PrintStream ps = new PrintStream(os);
		DataCursor<String> c = sdb.queryBeforeId(maxId);
		try {
			if (c.moveToFirst())
				ps.println(c.getData());
			else
				return;
			while (c.moveToNext()) {
				ps.println(c.getData());
			}
		} catch (Exception e) {
			return;
		} finally {
			c.close();
		}
		ps.close();

		boolean result = doUpload(os.toByteArray());
		if (result)
			sdb.deleteBeforeId(maxId);
	}

	private boolean doUpload(byte[] data) {
		if ((data == null) || (data.length <= 0)) {
			return false;
		}

		MyHttpClient httpClient = HttpClientFactory.getHttpClient();
		boolean result = false;
		try {
			HttpPost post = new HttpPost(URL);
			ByteArrayEntity entity = new ByteArrayEntity(data);
			post.setEntity(entity);
			HttpResponse response = httpClient.execute(post);
			result = response.getStatusLine().getStatusCode() / 100 == 2;
			entity.consumeContent();
		} catch (Exception e) {
		} finally {
			httpClient.recycle();
		}

		return result;
	}

	public boolean isClosed() {
		return closed;
	}

	public void close() {
		if (closed)
			return;
		if (sdb != null) {
		    sdb.close();
		}
		closed = true;
	}

	public boolean push(String data) {
		if (closed)
			return false;

		int count = 0;
		if (sdb != null) {
			count = sdb.count();
		}
		if (count < MAX) {
			char[] arr = data.toCharArray();
			int h = arr.length;
			for (char c : arr) {
				h = 31 * h + c;
			}
			String str = Integer.toHexString((0xFFFF & h) ^ (h >>> 16));
			while (str.length() < 4) {
				str = "0" + str;
			}
			Message msg = handler.obtainMessage(ADD_ITEM, data + "&s=" + str);
			return handler.sendMessage(msg);
		}

		return false;
	}

	public void force() {
		if (closed)
			return;
		handler.sendEmptyMessage(FORCE_UPLOAD);
	}
}
